1use std::sync::Arc;
2
3use crate::pp_log::{PpLog, pp_trace};
4
5use crate::{
6 buffer::MediaBuffer,
7 bus::{Bus, BusEvent},
8 control::ControlMsg,
9 element::{Context, Element, ElementType, Filter, Sink, Source, element_pp_log},
10 error::Result,
11 graph::{BranchId, BranchPlan, ElementId, GraphError, NodeInfo, PlannedEdge, PortRef},
12 pad::SrcPad,
13 queue::{OverflowPolicy, Queue},
14};
15
16pub struct ChainBuilder {
25 context: Arc<Context>,
26 elements: Vec<Box<dyn StageBuilder>>,
27 planned: Vec<PlannedNode>,
30 error: Option<GraphError>,
31}
32
33struct PlannedNode {
34 info: NodeInfo,
35 output_port: Arc<str>,
36}
37
38pub struct DetachedBranch {
41 pub(crate) root: Box<dyn Sink>,
42 pub(crate) plan: BranchPlan,
43}
44
45impl DetachedBranch {
46 pub fn root_id(&self) -> ElementId {
47 self.plan.root
48 }
49}
50
51trait StageBuilder: Send {
52 fn wrap(
53 self: Box<Self>,
54 downstream: Box<dyn Sink>,
55 bus: &Bus,
56 pipeline_id: &str,
57 ) -> Box<dyn Sink>;
58}
59
60struct DirectStage<T>(T);
61
62struct FlowTracer<T> {
65 inner: T,
66}
67
68impl<T: Element> Element for FlowTracer<T> {
69 fn name(&self) -> Arc<str> {
70 self.inner.name()
71 }
72
73 fn element_type(&self) -> ElementType {
74 self.inner.element_type()
75 }
76
77 fn graph_id(&self) -> Option<ElementId> {
78 self.inner.graph_id()
79 }
80
81 fn pp_log(&self) -> &PpLog {
82 self.inner.pp_log()
83 }
84
85 fn pp_log_mut(&mut self) -> &mut PpLog {
86 self.inner.pp_log_mut()
87 }
88}
89
90impl<T: Source> Source for FlowTracer<T> {
91 fn src_pads(&mut self) -> &mut [SrcPad] {
92 self.inner.src_pads()
93 }
94}
95
96impl<T: Sink> Sink for FlowTracer<T> {
97 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
98 let is_eos = buf.is_eos();
99 if is_eos {
100 pp_trace!(pp_log: self.inner.pp_log(), "event=eos phase=received");
101 }
102 let result = self.inner.consume(buf);
103 if is_eos {
104 match &result {
105 Ok(()) => pp_trace!(
106 pp_log: self.inner.pp_log(),
107 "event=eos phase=completed outcome=ok"
108 ),
109 Err(error) => pp_trace!(
110 pp_log: self.inner.pp_log(),
111 "event=eos phase=completed outcome=error error={error}"
112 ),
113 }
114 }
115 result
116 }
117
118 fn control(&mut self, msg: ControlMsg) -> Result<()> {
119 pp_trace!(
120 pp_log: self.inner.pp_log(),
121 "event=control control={msg:?} phase=received"
122 );
123 let result = self.inner.control(msg);
124 match &result {
125 Ok(()) => pp_trace!(
126 pp_log: self.inner.pp_log(),
127 "event=control control={msg:?} phase=completed outcome=ok"
128 ),
129 Err(error) => pp_trace!(
130 pp_log: self.inner.pp_log(),
131 "event=control control={msg:?} phase=completed outcome=error error={error}"
132 ),
133 }
134 result
135 }
136}
137
138impl<T> StageBuilder for DirectStage<T>
139where
140 T: Filter + 'static,
141{
142 fn wrap(
143 self: Box<Self>,
144 downstream: Box<dyn Sink>,
145 _bus: &Bus,
146 pipeline_id: &str,
147 ) -> Box<dyn Sink> {
148 let mut element = self.0;
149 *element.pp_log_mut() =
150 element_pp_log(element.element_type(), &element.name(), Some(pipeline_id));
151 element.src_pads()[0].link(downstream);
152 Box::new(FlowTracer { inner: element })
153 }
154}
155
156struct QueueStage {
157 id: ElementId,
158 name: String,
159 capacity: usize,
160 policy: OverflowPolicy,
161}
162
163struct TerminalTracer {
169 bus: Bus,
170 inner: Box<dyn Sink>,
171}
172
173impl Element for TerminalTracer {
174 fn name(&self) -> Arc<str> {
175 self.inner.name()
176 }
177
178 fn element_type(&self) -> ElementType {
179 self.inner.element_type()
180 }
181
182 fn graph_id(&self) -> Option<ElementId> {
183 self.inner.graph_id()
184 }
185
186 fn pp_log(&self) -> &PpLog {
187 self.inner.pp_log()
188 }
189
190 fn pp_log_mut(&mut self) -> &mut PpLog {
191 self.inner.pp_log_mut()
192 }
193}
194
195impl Sink for TerminalTracer {
196 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
197 let is_eos = buf.is_eos();
198 if is_eos {
199 pp_trace!(pp_log: self.inner.pp_log(), "event=eos phase=received");
200 }
201 let result = self.inner.consume(buf);
202 if is_eos {
203 match &result {
204 Ok(()) => {
205 pp_trace!(
206 pp_log: self.inner.pp_log(),
207 "event=eos phase=completed outcome=ok"
208 );
209 self.bus.post(
210 self.inner.pp_log(),
211 BusEvent::Eos {
212 element_type: self.inner.element_type(),
213 name: self.inner.name(),
214 },
215 );
216 }
217 Err(error) => pp_trace!(
218 pp_log: self.inner.pp_log(),
219 "event=eos phase=completed outcome=error error={error}"
220 ),
221 }
222 }
223 result
224 }
225
226 fn control(&mut self, msg: ControlMsg) -> Result<()> {
227 pp_trace!(
228 pp_log: self.inner.pp_log(),
229 "event=control control={msg:?} phase=received"
230 );
231 let result = self.inner.control(msg);
232 match &result {
233 Ok(()) => pp_trace!(
234 pp_log: self.inner.pp_log(),
235 "event=control control={msg:?} phase=completed outcome=ok"
236 ),
237 Err(error) => pp_trace!(
238 pp_log: self.inner.pp_log(),
239 "event=control control={msg:?} phase=completed outcome=error error={error}"
240 ),
241 }
242 result
243 }
244}
245
246impl StageBuilder for QueueStage {
247 fn wrap(
248 self: Box<Self>,
249 downstream: Box<dyn Sink>,
250 bus: &Bus,
251 pipeline_id: &str,
252 ) -> Box<dyn Sink> {
253 Box::new(Queue::spawn_with_policy(
254 self.name,
255 self.capacity,
256 downstream,
257 bus.for_element(self.id),
258 self.policy,
259 Some(pipeline_id),
260 ))
261 }
262}
263
264impl ChainBuilder {
265 pub fn new(context: Arc<Context>) -> Self {
269 Self {
270 context,
271 elements: Vec::new(),
272 planned: Vec::new(),
273 error: None,
274 }
275 }
276
277 pub fn pipe<T: Filter + 'static>(mut self, mut element: T) -> Self {
282 let name = element.name();
283 let pad_count = element.src_pads().len();
284 if pad_count != 1 && self.error.is_none() {
285 self.error = Some(GraphError::NotSingleOutput {
286 name: name.clone(),
287 count: pad_count,
288 });
289 }
290 let output_port = element
291 .src_pads()
292 .first()
293 .map(|pad| Arc::<str>::from(pad.name()))
294 .unwrap_or_else(|| "src".into());
295 self.planned.push(PlannedNode {
296 info: NodeInfo {
297 id: self.context.graph.reserve_element_id(),
298 element_type: element.element_type(),
299 name,
300 },
301 output_port,
302 });
303 self.elements.push(Box::new(DirectStage(element)));
304 self
305 }
306
307 pub fn queue(self, name: impl Into<String>, capacity: usize) -> Self {
311 self.queue_with_policy(name, capacity, OverflowPolicy::default())
312 }
313
314 pub fn queue_with_policy(
318 mut self,
319 name: impl Into<String>,
320 capacity: usize,
321 policy: OverflowPolicy,
322 ) -> Self {
323 let name: Arc<str> = name.into().into();
324 let id = self.context.graph.reserve_element_id();
325 self.planned.push(PlannedNode {
326 info: NodeInfo {
327 id,
328 element_type: ElementType::Queue,
329 name: name.clone(),
330 },
331 output_port: format!("{name}_src").into(),
332 });
333 self.elements.push(Box::new(QueueStage {
334 id,
335 name: name.to_string(),
336 capacity,
337 policy,
338 }));
339 self
340 }
341
342 pub fn to(self, mut terminal: Box<dyn Sink>) -> Result<DetachedBranch> {
347 if let Some(error) = self.error {
348 return Err(error.into());
349 }
350 *terminal.pp_log_mut() = element_pp_log(
351 terminal.element_type(),
352 &terminal.name(),
353 Some(&self.context.pipeline_id),
354 );
355 let terminal_info = NodeInfo {
356 id: terminal
357 .graph_id()
358 .unwrap_or_else(|| self.context.graph.reserve_element_id()),
359 element_type: terminal.element_type(),
360 name: terminal.name(),
361 };
362 let terminal_id = terminal_info.id;
363 let mut nodes: Vec<_> = self.planned.iter().map(|node| node.info.clone()).collect();
364 nodes.push(terminal_info);
365 let edges = nodes
366 .windows(2)
367 .enumerate()
368 .map(|(index, pair)| PlannedEdge {
369 from: PortRef {
370 element: pair[0].id,
371 port: self.planned[index].output_port.clone(),
372 },
373 to: PortRef {
374 element: pair[1].id,
375 port: "sink".into(),
376 },
377 })
378 .collect();
379 let root_id = nodes.first().expect("terminal always supplies one node").id;
380 let terminal: Box<dyn Sink> = Box::new(TerminalTracer {
381 bus: self.context.bus.for_element(terminal_id),
382 inner: terminal,
383 });
384 let root = self
385 .elements
386 .into_iter()
387 .rev()
388 .fold(terminal, |downstream, stage| {
389 stage.wrap(downstream, &self.context.bus, &self.context.pipeline_id)
390 });
391 Ok(DetachedBranch {
392 root,
393 plan: BranchPlan {
394 nodes,
395 edges,
396 root: root_id,
397 },
398 })
399 }
400
401 pub fn build(self, terminal: Box<dyn Sink>) -> Result<DetachedBranch> {
402 self.to(terminal)
403 }
404}
405
406impl Context {
407 pub fn branch(self: &Arc<Self>) -> ChainBuilder {
408 ChainBuilder::new(self.clone())
409 }
410
411 pub fn attach<S: Source>(
412 &self,
413 source: &mut S,
414 pad_index: usize,
415 branch: DetachedBranch,
416 ) -> Result<BranchId> {
417 let pads = source.src_pads();
418 let pad_count = pads.len();
419 let pad = pads.get_mut(pad_index).ok_or(GraphError::PadOutOfRange {
420 index: pad_index,
421 pad_count,
422 })?;
423 self.attach_pad(pad, branch)
424 }
425
426 pub(crate) fn attach_pad(&self, pad: &mut SrcPad, branch: DetachedBranch) -> Result<BranchId> {
427 if pad.is_linked() {
428 return Err(GraphError::PadAlreadyLinked(pad.name().to_owned()).into());
429 }
430 let from_port: Arc<str> = pad.name().into();
431 let DetachedBranch { root, plan } = branch;
432 Ok(self
433 .graph
434 .attach_with(self.source_id, from_port, plan, |_| {
435 pad.link(root);
436 Ok(())
437 })?)
438 }
439}